﻿using System;
using WiMo.Games.Premium.GDIDisplay.ImageAPI;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using WiMo.Games.Premium.GDIDisplay.Drawables;
using gdi = WiMo.Games.Premium.GDIDisplay.DirectDraw;
using imgBitmapdata = WiMo.Games.Premium.GDIDisplay.ImageAPI.BitmapData;
using WiMo.Games.Premium.GDIDisplay.DirectDraw;

namespace WiMo.Games.Premium.GDIDisplay
{
    class WiMoGraphics : IDisposable, IWiMoGraphics
    {
        [DllImport("coredll", EntryPoint = "GetDC", SetLastError = true)]
        private static extern IntPtr GetDC(IntPtr hWnd);

        [DllImport("coredll.dll", EntryPoint = "ReleaseDC", SetLastError = true)]
        private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        private Graphics _graphics;
        Bitmap _buffer;
        Size _size;

        private DirectDraw.DirectDrawGraphics _ddGraphics;

        public WiMoGraphics(Size size, IntPtr hwnd)
        {
            _size = size;
            _buffer = new Bitmap(size.Width, size.Height);
            _ddGraphics = new WiMo.Games.Premium.GDIDisplay.DirectDraw.DirectDrawGraphics(hwnd, WiMo.Games.Premium.GDIDisplay.DirectDraw.BackbufferMode.Software);
            DirectDraw.DirectDrawGraphics.Init();

            Clear();

            _graphics = Graphics.FromImage(_buffer);
        }

        public string Name
        {
            get { return "GDI - Bitmap Backbuffer"; }
        }

        public void RenderBackground()
        {
            _ddGraphics.ScreenSurface.Fill(Color.CornFlowerBlue);
            //var bgBrush = new SolidBrush(Color.CornFlowerBlue.ToDrawingColor());
            //_graphics.FillRectangle(bgBrush, 0, 0, _bounds.Width, _bounds.Height);
            //bgBrush.Dispose();
        }

        public void Reset()
        {
            if (_graphics != null)
                _graphics.Dispose();

            _graphics = Graphics.FromImage(_buffer);

        }

        public void Clear()
        {
            Clear(Color.Black);
        }

        public void Clear(Color color)
        {
            using (var gr = Graphics.FromImage(_buffer))
                gr.Clear(color.ToDrawingColor());
        }

        public void Dispose()
        {
            _graphics.Dispose();
            _buffer.Dispose();
        }

        public void DrawImage(Image image, int x, int y)
        {
            _graphics.DrawImage(image, x, y);
        }

        public void DrawImage(Image image, Location location, Color colorKey)
        {
            _graphics.DrawImage(image, location, colorKey);
        }

        public void DrawImage(Image image, Location location)
        {
            _graphics.DrawImage(image, location.X, location.Y);
        }

        public void DrawImage(Image image, Rectangle dst, Rectangle src, Color colorKey)
        {
            if (colorKey != Color.Transparent)
            {
                var imageAttr = new ImageAttributes();
                imageAttr.SetColorKey(colorKey.ToDrawingColor(), colorKey.ToDrawingColor());
                _graphics.DrawImage(image, dst.ToDrawingRect(), src.X, src.Y, src.Width, src.Height, GraphicsUnit.Pixel, imageAttr);
                imageAttr.Dispose();
            }
            else
                _graphics.DrawImage(image, dst.ToDrawingRect(), src.ToDrawingRect(), GraphicsUnit.Pixel);
        }

        public void DrawImage(Image image, Rectangle dst, Rectangle src)
        {
            _graphics.DrawImage(image, dst.ToDrawingRect(), src.ToDrawingRect(), GraphicsUnit.Pixel);
        }

        public void FillRectangle(Color color, int x, int y, int width, int height)
        {
            var brush = new SolidBrush(color.ToDrawingColor());
            _graphics.FillRectangle(brush, x, y, width, height);
            brush.Dispose();
        }

        public void DrawRectangle(Color borderColor, Color fillColor, Rectangle rect, byte alpha)
        {
            _graphics.DrawRectangle(rect, borderColor, fillColor, alpha);
        }

        public void DrawImage(IImage image, Rectangle dest, Rectangle src)
        {
            _graphics.DrawImageAlphaChannel(image, dest, src);
        }

        public void FillRectangle(Color color, Rectangle rect)
        {
            var solidBrush = new SolidBrush(color.ToDrawingColor());
            _graphics.FillRectangle(solidBrush, rect.ToDrawingRect());
            solidBrush.Dispose();
        }

        public void FillEllipse(Color color, Location point, Size size)
        {
            if (color == Color.Transparent)
                return;

            var brush = new SolidBrush(color.ToDrawingColor());
            _graphics.FillEllipse(brush, point.X, point.Y, size.Width, size.Height);
            brush.Dispose();
        }

        public void DrawEllipse(Color color, int width, Location point, Size size)
        {
            if (color == Color.Transparent || width == 0)
                return;

            var pen = new Pen(color.ToDrawingColor(), Convert.ToSingle(width));
            _graphics.DrawEllipse(pen, point.X, point.Y, size.Width, size.Height);
            pen.Dispose();
        }

        public void DrawLine(Color color, int width, Location start, Location end)
        {
            var pen = new Pen(color.ToDrawingColor(), Convert.ToSingle(width));
            _graphics.DrawLine(pen, start.X, start.Y, end.X, end.Y);
            pen.Dispose();
        }

        public void DrawLines(Color color, int width, Point[] points)
        {
            if (color == Color.Transparent || width == 0)
                return;

            var pen = new Pen(color.ToDrawingColor(), Convert.ToSingle(width));
            _graphics.DrawLines(pen, points);
            pen.Dispose();
        }

        public void FillPolygon(Color color, Point[] points)
        {
            if (color == Color.Transparent)
                return;

            var brush = new SolidBrush(color.ToDrawingColor());
            _graphics.FillPolygon(brush, points);
            brush.Dispose();

        }

        public Size MeasureString(string text, Font font)
        {
            SizeF size = _graphics.MeasureString(text, font);
            return new Size(Convert.ToSingle(size.Width), Convert.ToSingle(size.Height));
        }

        public void RenderBackbuffer(IntPtr hwnd)
        {
            var dc = GetDC(hwnd);
            var gr = Graphics.FromHdc(dc);
            gr.DrawImage(_buffer, 0, 0);
            gr.Dispose();
            ReleaseDC(hwnd, dc);

            //_ddGraphics.Flip();
        }

        private const int DIB_RGB_COLORS = 0;

        private void RenderIImage(WiMoImage image, Location location)
        {
            var qTimer = new HighResolutionStopWatch();
            qTimer.Start();

            if (image.ImagingImage == null)
                image.CreateImagingImage();

            var dc = _graphics.GetHdc();

            var destRect = new System.Drawing.Rectangle(location.X, location.Y, location.X + image.Size.Width, location.Y + image.Size.Height);
            image.ImagingImage.Draw(dc, ref destRect, IntPtr.Zero);

            _graphics.ReleaseHdc(dc);

            qTimer.Stop();
     //       System.Diagnostics.Debug.WriteLine("Q-> " + qTimer.ToString());
        }

        private void RenderSurfaceImage(WiMoImage image, Location location)
        {
            if (image.SurfaceImage == null)
                image.CreateSurfaceImage(_ddGraphics);
             
            var destRect = new tagRECT(location.X, location.Y, location.X + image.Size.Width, location.Y + image.Size.Height);
            var srcRect = new tagRECT(0, 0, image.Size.Width, image.Size.Height);
            //image.SurfaceImage.SetColorKey(image.ColorKey, ColorKeyFlags.SRCBLT);

            var qTimer = new HighResolutionStopWatch();
            qTimer.Start();
            _ddGraphics.ScreenSurface.Draw(ref destRect, image.SurfaceImage, ref srcRect, BltFlags.DDBLT_KEYSRC);
            //_ddGraphics.ScreenSurface.DrawAlpha(ref destRect, image.SurfaceImage, ref srcRect);
            qTimer.Stop();

            System.Diagnostics.Debug.WriteLine("DD-> " + qTimer.ToString());
        }

        #region RenderIBitmapImage
        private void RenderIBitmapImage(WiMoImage image, Location location)
        {
            var qTimer = new HighResolutionStopWatch();
            qTimer.Start();

            if (image.ImagingImage == null)
                image.CreateImagingImage();

            //var rect = new System.Drawing.Rectangle(0, 0, image.Size.Width, image.Size.Height);
            //imgBitmapdata bmpData;
            //image.ImagingBitmap.LockBits(ref rect, 0, PixelFormatID.PixelFormat32bppRGB, out bmpData);
            //DirectDraw.GDI.SelectObject(hdc, bmpData.Scan0);

            using (var bitmap = new Bitmap(image.Size.Width, image.Size.Height, PixelFormat.Format16bppRgb565))
            {
                using (Graphics gr = Graphics.FromImage(bitmap))
                {
                    gr.Clear(System.Drawing.Color.Aqua);
                    //var srcDC = gr.GetHdc();

                    var hbm = bitmap.GetHbitmap();
                    var targetDC = _buffer.GetHbitmap();
                  
                    DirectDraw.GDI.BitBlt(targetDC, location.X, location.Y, image.Size.Width, image.Size.Height, hbm, 0, 0, gdi.TernaryRasterOperations.SRCCOPY);

                    //DirectDraw.GDI.DeleteDC(srcDC);
                    DirectDraw.GDI.DeleteObject(hbm);
                    DirectDraw.GDI.DeleteObject(targetDC);
                }
            }
            //image.ImagingBitmap.UnlockBits(ref bmpData);
            //_graphics.ReleaseHdc(sdc);

            qTimer.Stop();
            System.Diagnostics.Debug.WriteLine("Q-> " + qTimer.ToString());
        }
        #endregion

        private void RenderBitmap(WiMoImage image, Location location)
        {
            var dTimer = new HighResolutionStopWatch();
            dTimer.Start();

            var type = string.Empty;

            if (image.Transparency != 0xFF || image.ColorKey.A != 0xFF)
            {
                var transparency = image.Transparency == 0xFF ? image.ColorKey.A : image.Transparency;

                type = "TRANS";
                _graphics.DrawAlpha(image.BitmapImage, transparency, location);                
            }
            else
            {
                type = "SOLID";
                _graphics.DrawImage(image.BitmapImage, location, image.ColorKey);
            }

            dTimer.Stop();
        //    System.Diagnostics.Debug.WriteLine("D-> " + type + " " + dTimer.ToString());        
        }


        public void DrawImage(WiMoImage image, Location location)
        {
            switch (image.RenderStrategy)
            {
                case WiMo.Games.Drawables.RenderStrategy.Standard:
                case WiMo.Games.Drawables.RenderStrategy.Fast:
                    RenderBitmap(image, location);
                    break;

                case WiMo.Games.Drawables.RenderStrategy.Quality:
                    //RenderIBitmapImage(image, location);
                    RenderIImage(image, location);
                    //RenderSurfaceImage(image, location);
                    break;
            }

        }

        public void DrawImage(WiMoImage image, Location location, Rectangle dest)
        {
            _graphics.DrawImage(image.BitmapImage, location, image.ColorKey);
        }
    }
}
